﻿// -------------------------------------------------------------------------
//    @FileName         :    NFExprCheck.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-09-30
//    @Email			:    445267987@qq.com
//    @Module           :    NFExprCheck
//    @Desc             :
//
// -------------------------------------------------------------------------

#include "NFExprCheck.h"

CExprSymbol::CExprSymbol():m_llfNum(0.0f), m_eOp(EN_EXPR_OP_NONE)
{
}

CExprSymbol::CExprSymbol(double llfNum):m_llfNum(llfNum), m_eOp(EN_EXPR_OP_NONE)
{
}

CExprSymbol::CExprSymbol(enExprOp eOp):m_llfNum(0.0f), m_eOp(eOp)
{
}

CExprSymbol::~CExprSymbol()
{
}

std::string CExprSymbol::GetOpStr(enExprOp eOp)
{
    switch(eOp)
    {
        case EN_EXPR_OP_PLUS:
            return "+";
        case EN_EXPR_OP_SUB:
            return "-";
        case EN_EXPR_OP_MUL:
            return "*";
        case EN_EXPR_OP_DIV:
            return "/";
        default:
            break;
    }

    return " ";
}

bool CExprSymbol::IsNum()
{
    return m_eOp == EN_EXPR_OP_NONE;
}

bool CExprSymbol::IsOp()
{
    return !IsNum();
}

double CExprSymbol::GetNum() const
{
    return m_llfNum;
}

enExprOp CExprSymbol::GetOp() const
{
    return m_eOp;
}

std::string CExprSymbol::DebugString()
{
    if(IsNum())
    {
        return NF_SPRINTF("%.8lf", m_llfNum);
    }
    else
    {
        return GetOpStr(m_eOp);
    }
}

CExprCheck::CExprCheck():m_bNeedCalc(false), m_llfRet(0.0f)
{
}

CExprCheck::~CExprCheck()
{
}

double CExprCheck::GetRet() const
{
    return m_llfRet;
}

bool CExprCheck::NeedCalc() const
{
    return m_bNeedCalc;
}

int CExprCheck::SetNeedCalc()
{
    m_bNeedCalc = true;
    ClearOverflow();
    return 0;
}

int CExprCheck::ClearNeedCalc()
{
    m_bNeedCalc = false;

    return 0;
}

bool CExprCheck::IsOverflow() const
{
    return m_bOverflow;
}

int CExprCheck::SetOverflow()
{
    m_bOverflow = true;
    return 0;
}

int CExprCheck::ClearOverflow()
{
    m_bOverflow = false;
    return 0;
}

int CExprCheck::PushNum(double llfNum)
{
    CExprSymbol stSymbol(llfNum);
    m_vecSymbol.push_back(stSymbol);

    SetNeedCalc();

    return 0;
}

int CExprCheck::PushOp(enExprOp eOp)
{
    CExprSymbol stSymbol(eOp);
    m_vecSymbol.push_back(stSymbol);

    SetNeedCalc();
    return 0;
}

int CExprCheck::PushOp(char c)
{
    int iRetCode = 0;

    switch(c)
    {
        case '+':
            iRetCode = PushOp(EN_EXPR_OP_PLUS);
            break;
        case '-':
            iRetCode = PushOp(EN_EXPR_OP_SUB);
            break;
        case '*':
            iRetCode = PushOp(EN_EXPR_OP_MUL);
            break;
        case '/':
            iRetCode = PushOp(EN_EXPR_OP_DIV);
            break;
        default:
            iRetCode = -1;
            break;
    }

    CHECK_ERR(0, iRetCode, "error op char: {}", c);

    return 0;
}

int CExprCheck::CalcExprInt64()
{
    return CalcExpr(LLONG_MIN, LLONG_MAX);
}

int CExprCheck::CalcExpr(double llfMinBound, double llfMaxBound)
{
    if(!NeedCalc())
    {
        LOG_ERR(0, -1, "not need calc");
        return 0;
    }

    int iRetCode = 0;

    std::stack<double> staNum;

    for(int i = 0; i < (int)m_vecSymbol.size(); ++i)
    {
        if(m_vecSymbol[i].IsNum())
        {
            staNum.push(m_vecSymbol[i].GetNum());
        }
        else
        {
            if(staNum.size() >= 2)
            {
                double llfNum1 = staNum.top();
                staNum.pop();
                double llfNum2 = staNum.top();
                staNum.pop();

                double llfRet = CalcExpr(llfNum2, llfNum1, m_vecSymbol[i].GetOp());
                staNum.push(llfRet);

                if(llfRet < llfMinBound || llfRet > llfMaxBound)
                {
                    SetOverflow();
                }
            }
            else
            {
                iRetCode = -1;
                break;
            }
        }
    }
    CHECK_ERR(0, iRetCode, "calc expr error:{}", DebugString());

    if(staNum.size() > 0)
    {
        m_llfRet = staNum.top();
    }
    else
    {
        iRetCode = -1;
    }
    CHECK_ERR(0, iRetCode, "calc expr error:{}", DebugString());

#ifdef EXPR_LOG
    LOG_DEBUG(0, "calc expr success: {}", DebugString());
#endif

    ClearNeedCalc();

    return 0;
}

double CExprCheck::CalcExpr(double llfNum1, double llfNum2, enExprOp eOp)
{
    double llfRet = 0.0f;

    switch(eOp)
    {
        case EN_EXPR_OP_PLUS:
            llfRet = llfNum1 + llfNum2;
            break;
        case EN_EXPR_OP_SUB:
            llfRet = llfNum1 - llfNum2;
            break;
        case EN_EXPR_OP_MUL:
            llfRet = llfNum1 * llfNum2;
            break;
        case EN_EXPR_OP_DIV:
            llfRet = llfNum1 / llfNum2;
            break;
        default:
            break;
    }

#ifdef EXPR_LOG
    LOG_DEBUG(0, "calc expr ret: {} num1:{} num2:{} op:{}", llfRet, llfNum1, llfNum2, eOp);
#endif

    return llfRet;
}

std::string CExprCheck::DebugString()
{
    std::string str;

    for(int i = 0; i < (int)m_vecSymbol.size(); ++i)
    {
        str += m_vecSymbol[i].DebugString();
        str += " ";
    }

    return str.c_str();
}
